package com.yourenbang.lingyun.transaction.web.service.impl.pay.withdraw.channel;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yourenbang.lingyun.constants.BizCodeMessages;
import com.yourenbang.lingyun.constants.enums.PlatNoEnums;
import com.yourenbang.lingyun.constants.enums.pay.PayFromEnum;
import com.yourenbang.lingyun.constants.enums.pay.PayTypeEnum;
import com.yourenbang.lingyun.core.exception.SysBizException;
import com.yourenbang.lingyun.core.message.Result;
import com.yourenbang.lingyun.core.util.BizAssertUtils;
import com.yourenbang.lingyun.core.util.Generator;
import com.yourenbang.lingyun.core.util.KLog;
import com.yourenbang.lingyun.core.util.json.JsonUtils;
import com.yourenbang.lingyun.domain.MerchantPaymentSign;
import com.yourenbang.lingyun.domain.MerchantPaymentSignExample;
import com.yourenbang.lingyun.domain.UserBase;
import com.yourenbang.lingyun.mapper.MerchantPaymentSignMapper;
import com.yourenbang.lingyun.mapper.UserBaseMapper;
import com.yourenbang.lingyun.transaction.config.AcmGlobalParams;
import com.yourenbang.lingyun.transaction.exception.WichdrawFailException;
import com.yourenbang.lingyun.transaction.mapper.TransactionFundAccountWithdrawPaymentMapper;
import com.yourenbang.lingyun.transaction.util.DateUtil;
import com.yourenbang.lingyun.transaction.util.fusuilinggong.FuSuiLingGongUtil;
import com.yourenbang.lingyun.transaction.util.linghuisuan.LinghuisuanUtil;
import com.yourenbang.lingyun.transaction.web.domain.dto.pay.fusuilinggong.*;
import com.yourenbang.lingyun.transaction.web.domain.po.FundAccountWithdrawPayment;
import com.yourenbang.lingyun.transaction.web.domain.vo.pay.hjtx.AgentpayVO;
import com.yourenbang.lingyun.transaction.web.service.pay.withdraw.channel.FuSuiLingGongService;
import com.yourenbang.transaction.api.service.pay.PayTypeApiService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.*;

/**
 * 福穗灵工
 */
@Service
@Slf4j
public class FuSuiLingGongServiceImpl implements FuSuiLingGongService {
    private static final String log_suffix = "福穗灵工";
    @Autowired
    private PayTypeApiService payTypeApiService;
    @Resource
    UserBaseMapper userBaseMapper;
    @Resource
    MerchantPaymentSignMapper merchantPaymentSignMapper;
    @Autowired
    private AcmGlobalParams acmGlobalParams;
    @Resource
    private TransactionFundAccountWithdrawPaymentMapper fundAccountWithdrawPaymentMapper;

    private AgentPayParamDTO initParam() {
        try {

            Map<String, String> typeParams = payTypeApiService.getPayParams(PayTypeEnum.FUSUILINGGONG, PayFromEnum.yxy_withdraw_ally_all);
            AgentPayParamDTO agentPayParamDTO = JsonUtils.convertValue(typeParams, AgentPayParamDTO.class);
            log.info("【{}】支付渠道参数:{}", log_suffix, JSON.toJSONString(agentPayParamDTO));
            return agentPayParamDTO;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    @Override
    public AgentpayVO agentPay(FuSuiLingGongAgentPayDTO dto) {
        //证明上传-》结算发放-》审核下发结算
        //证明上传
        uploadEvidence(dto);
        //结算发放
        Result<UploadPlanResponse> uploadPlanResult = uploadPlan(dto);
        //审核下发结算
//        grantPlan(uploadPlanResult.getData());

        AgentpayVO vo = new AgentpayVO();
        vo.setOrderNo(dto.getOrderNo());
        vo.setSerialNumber(uploadPlanResult.getData().getBizNo());
        return vo;
    }

    private void uploadEvidence(FuSuiLingGongAgentPayDTO dto) {
        String nowDate = DateUtil.getDateTime();
        AgentPayParamDTO agentPayParamDTO = initParam();

        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("taskId", agentPayParamDTO.getTaskId());

        // 单条证据详情
        HashMap<String, String> evidenceMap = new HashMap<>(10);
        evidenceMap.put("orderTime", nowDate);
        evidenceMap.put("userName", dto.getAccountName());
        evidenceMap.put("orderAmount", dto.getAmt().toPlainString());
        evidenceMap.put("orderNo", dto.getOrderNo());
        String evidenceJsonStr = JSONObject.toJSONString(evidenceMap);

        // 外层关联业务内容
        Map<String, String> cloMap = new HashMap<>();
        cloMap.put("bizNo", dto.getOrderNo());
        cloMap.put("idCard", StringUtils.upperCase(dto.getIdCard()));
        cloMap.put("dataTime", StringUtils.left(nowDate, 10));
        cloMap.put("evidence", evidenceJsonStr);
        cloMap.put("fileUrl", acmGlobalParams.getLingyunHost() + "/transaction/fund/withdraw/fusuilinggong/" + dto.getOrderNo()+".xls");
        paramsMap.put("evidences", Collections.singletonList(cloMap));

        Result result = doRequest("/api/open/uploadEvidence", JSONObject.toJSONString(paramsMap), null);
        if (result.isFail()) {
            throw new WichdrawFailException(result.getDesc());
        }
    }

    private Result<UploadPlanResponse> uploadPlan(FuSuiLingGongAgentPayDTO dto) {
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("accountNumber", dto.getAccountNo());
        paramsMap.put("afterTaxAmount", dto.getAmt().toPlainString());
        paramsMap.put("grantType", "银行卡");
        paramsMap.put("idCard", StringUtils.upperCase(dto.getIdCard()));
        paramsMap.put("mobile", dto.getPhone());
        paramsMap.put("outBizNo", dto.getOrderNo());

        AgentPayParamDTO agentPayParamDTO = initParam();
        String remark = StringUtils.isBlank(dto.getRemark()) ? "收益" : dto.getRemark();
        paramsMap.put("remark", remark);
        paramsMap.put("taskNo", agentPayParamDTO.getTaskId());
        paramsMap.put("userName", dto.getAccountName());

        Result<UploadPlanResponse> result = doRequest("/api/open/uploadPlan", JSONObject.toJSONString(paramsMap), UploadPlanResponse.class);
        if (result.isSuccess()) {
            return result;
        }
        throw new WichdrawFailException(result.getDesc());
    }

    private void grantPlan(UploadPlanResponse data) {
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("outBizNo", data.getOutBizNo());
        //发放状态 1-发放通过 2-发放拒绝
        paramsMap.put("grantStatus", 1);
        Result result = doRequest("/api/open/grantPlan", JSONObject.toJSONString(paramsMap), null);
        if (result.isFail()) {
            throw new WichdrawFailException(result.getDesc());
        }
    }

    @Override
    public boolean checkAgentPayResult(FuSuiLingGongAgentPayQueryDTO dto) {
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("outBizNo", dto.getOrderNo());

        Result<CheckAgentPayResponse> result = doRequest("/api/open/queryPlan", JSONObject.toJSONString(paramsMap), CheckAgentPayResponse.class);
        if (result.isFail()) {
            return false;
        }
        CheckAgentPayResponse agentPayResponse = result.getData();
        return agentPayResponse.getAuditStatus().equals(CheckAgentPayResponse.AUDIT_STATUS_1)
                && agentPayResponse.getGrantStatus().equals(CheckAgentPayResponse.GRANT_STATUS_1)
                && agentPayResponse.getPayStatus().equals(CheckAgentPayResponse.PAY_STATUS_3);
    }

    @Override
    public Result<FundAccountWithdrawPayment> withdrawNotice(String param) {
        CheckAgentPayResponse checkAgentPayResponse = JSONObject.parseObject(param, CheckAgentPayResponse.class);

        String orderSn = checkAgentPayResponse.getBizOutNo();
        FundAccountWithdrawPayment payment = fundAccountWithdrawPaymentMapper.findByOrderSn(PlatNoEnums.YXY.getCode(), orderSn);
        if (Objects.isNull(payment)) {
            KLog.error("【{}提现回调】未找到提现订单,入参:{}", log_suffix, checkAgentPayResponse);
            return Result.builder().fail(BizCodeMessages.ORDER_NO_EXISTS);
        }
        payment.setPlatNo(PlatNoEnums.YXY.getCode());

        if (checkAgentPayResponse.getAuditStatus().equals(CheckAgentPayResponse.AUDIT_STATUS_2)
                || checkAgentPayResponse.getAuditStatus().equals(CheckAgentPayResponse.AUDIT_STATUS_3)
                || checkAgentPayResponse.getGrantStatus().equals(CheckAgentPayResponse.GRANT_STATUS_2)
                || checkAgentPayResponse.getPayStatus().equals(CheckAgentPayResponse.PAY_STATUS_4)
                || checkAgentPayResponse.getPayStatus().equals(CheckAgentPayResponse.PAY_STATUS_5)) {
            KLog.error("【{}提现回调】提现失败,入参:{}", log_suffix, checkAgentPayResponse);
            Result<FundAccountWithdrawPayment> result = Result.builder().fail(BizCodeMessages.TRANSACTION_WITHDRAW_FAIL);
            result.setData(payment);
            return result;
        } else if (checkAgentPayResponse.getAuditStatus().equals(CheckAgentPayResponse.AUDIT_STATUS_1)
                && checkAgentPayResponse.getGrantStatus().equals(CheckAgentPayResponse.GRANT_STATUS_1)
                && checkAgentPayResponse.getPayStatus().equals(CheckAgentPayResponse.PAY_STATUS_3)) {
            return Result.builder().success(payment);
        } else {
            return Result.builder().fail(BizCodeMessages.TRANSACTION_WITHDRAW_PROCESS);
        }
    }

    @Override
    public void signNotice(String param) {

    }

    @Override
    public boolean alreadySign(String userBaseId) {
        UserBase userBase = userBaseMapper.selectByPrimaryKey(userBaseId);
        if (ObjectUtils.isEmpty(userBase)) {
            return false;
        }
        if (StringUtils.isBlank(userBase.getIdNumber())) {
            return false;
        }
        MerchantPaymentSignExample merchantPaymentSignExample = new MerchantPaymentSignExample();
        merchantPaymentSignExample.createCriteria()
                .andSignChannelTypeEqualTo(PayTypeEnum.FUSUILINGGONG.getCode())
                .andIdNumberEqualTo(userBase.getIdNumber())
                .andSignStateEqualTo(LinghuisuanUtil.SIGN_STATUS_DIANZI_DONE);
        List<MerchantPaymentSign> merchantPaymentSigns = merchantPaymentSignMapper.selectByExample(merchantPaymentSignExample);
        String peopleId = "1122334455667788";
        if (CollectionUtils.isNotEmpty(merchantPaymentSigns) && merchantPaymentSigns.get(0).getSignState().compareTo(LinghuisuanUtil.SIGN_STATUS_DIANZI_DONE) == 0) {
            return true;
        }
        if (CollectionUtils.isNotEmpty(merchantPaymentSigns)) {
            peopleId =  merchantPaymentSigns.get(0).getThirdId();
        }
        //查询用户签约状态
        Result<QueryPeopleResponse> queryResult = queryPeople(peopleId);
        if(queryResult.isFail()){
            throw new WichdrawFailException("获取用户签约状态失败," + queryResult.getDesc());
        }
        if(queryResult.getData() != null){
            // 取第一个签约记录进行处理
            QueryPeopleResponse peopleResponse = queryResult.getData();
            if(peopleResponse.getSignStatus().equals(2) && peopleResponse.getSignType().equals(1)){
                throw new WichdrawFailException("请先完成签约再提现" + peopleResponse.getSignUrl());
            }
            if(peopleResponse.getSignStatus().equals(3) && peopleResponse.getSignType().equals(1)){
                MerchantPaymentSign merchantPaymentSign = new MerchantPaymentSign();
                merchantPaymentSign.setThirdId(peopleResponse.getPeopleId());
                merchantPaymentSign.setContractUrl(peopleResponse.getSignUrl());
                merchantPaymentSign.setSignState(LinghuisuanUtil.SIGN_STATUS_DIANZI_DONE);
                merchantPaymentSign.setMerchantPaymentSignId(merchantPaymentSigns.get(0).getMerchantPaymentSignId());
                int inSing = merchantPaymentSignMapper.updateByPrimaryKeySelective(merchantPaymentSign);
                BizAssertUtils.assertOne(inSing, "更新签约记录失败");
                return true;
            }
        }
        //调用签约状态
        Result<UploadPeopleResponse> result = uploadPeople(userBase);
        if (result.isFail()) {
            throw new WichdrawFailException("调用签约状态失败," + result.getDesc());
        }
        UploadPeopleResponse uploadPeopleResponse = result.getData();
        saveMerchantSign(userBase,uploadPeopleResponse,merchantPaymentSigns);
        //return StringUtils.equals(uploadPeopleResponse.getSignStatus(), UploadPeopleResponse.SIGN_STATUS_3);
        return false;
    }

    /**
     * 保存签约信息
     */
    private void saveMerchantSign(UserBase userBase, UploadPeopleResponse uploadPeopleResponse, List<MerchantPaymentSign> merchantPaymentSigns) {
        if (CollectionUtils.isEmpty(merchantPaymentSigns)) {
            MerchantPaymentSign merchantPaymentSign = new MerchantPaymentSign();
            merchantPaymentSign.setSignChannelType(PayTypeEnum.FUSUILINGGONG.getCode());
            merchantPaymentSign.setThirdId(uploadPeopleResponse.getPeopleId());
            merchantPaymentSign.setUserBaseId(userBase.getUserBaseId());
            merchantPaymentSign.setIdNumber(userBase.getIdNumber());
            merchantPaymentSign.setCallbackData(uploadPeopleResponse.toString());
            merchantPaymentSign.setContractUrl(uploadPeopleResponse.getSignUrl());
            merchantPaymentSign.setSignState(StringUtils.equals(uploadPeopleResponse.getSignStatus(), UploadPeopleResponse.SIGN_STATUS_3) ?
                    LinghuisuanUtil.SIGN_STATUS_DIANZI_DONE : LinghuisuanUtil.SIGN_STATUS_WAIT);
            int inSing = merchantPaymentSignMapper.insertSelective(merchantPaymentSign);
            BizAssertUtils.assertOne(inSing, "添加签约记录失败");
        } else {
            MerchantPaymentSign merchantPaymentSign = new MerchantPaymentSign();
            merchantPaymentSign.setThirdId(uploadPeopleResponse.getPeopleId());
            merchantPaymentSign.setContractUrl(uploadPeopleResponse.getSignUrl());
            merchantPaymentSign.setSignState(StringUtils.equals(uploadPeopleResponse.getSignStatus(), UploadPeopleResponse.SIGN_STATUS_3) ?
                    LinghuisuanUtil.SIGN_STATUS_DIANZI_DONE : LinghuisuanUtil.SIGN_STATUS_WAIT);
            merchantPaymentSign.setMerchantPaymentSignId(merchantPaymentSigns.get(0).getMerchantPaymentSignId());
            int inSing = merchantPaymentSignMapper.updateByPrimaryKeySelective(merchantPaymentSign);
            BizAssertUtils.assertOne(inSing, "更新签约记录失败");
        }
    }

    private Result<UploadPeopleResponse> uploadPeople(UserBase userBase) {
        AgentPayParamDTO agentPayParamDTO = initParam();

        UploadPeopleRequest request = new UploadPeopleRequest();
        request.setTaskNo(agentPayParamDTO.getTaskId());
        request.setUserName(userBase.getUserName());
        request.setIdCard(userBase.getIdNumber());
        request.setMobile(userBase.getPhone());
        request.setIsSendSms(1);
        return doRequest("/api/open/uploadPeople", JSONObject.toJSONString(request), UploadPeopleResponse.class);
    }

    private Result<QueryPeopleResponse> queryPeople(String peopleId) {
        AgentPayParamDTO agentPayParamDTO = initParam();

        QueryPeopleRequest request = new QueryPeopleRequest();
        request.setPeopleId(peopleId);
//        request.setIdCard(userBase.getIdNumber());
        return doRequest("/api/open/queryPeopleList", JSONObject.toJSONString(request), QueryPeopleResponse.class);
    }

    private <T> Result<T> doRequest(String uri, String bizJson, Class<T> response) {
        AgentPayParamDTO agentPayParamDTO = initParam();
        if (Objects.isNull(agentPayParamDTO)) {
            return Result.builder().fail(BizCodeMessages.UNKNOWN_ERROR, "获取配置参数失败");
        }
        // 毫秒
        String currentTimeMillis = String.valueOf(System.currentTimeMillis());
        // 长度最大32位
        String nonce = Generator.nextUUID();
        // 固定参数
        Map<String, String> param = new HashMap<String, String>();
        param.put("appId", agentPayParamDTO.getAppKey());
        param.put("nonce", nonce);
        param.put("timestamp", currentTimeMillis);
        param.put("bizContent", bizJson);
        String sign = null;
        String sortParams = FuSuiLingGongUtil.sortParams(param);
        String sb = FuSuiLingGongUtil.splice(agentPayParamDTO.getAppSecret(), sortParams);
        try {
            sign = FuSuiLingGongUtil.sign(sb, currentTimeMillis, agentPayParamDTO.getAppSecret());
        } catch (Exception e) {
            log.error(log_suffix + "加签失败", e);
        }
        param.put("sign", sign);
        String result = HttpUtil.post(agentPayParamDTO.getUri() + uri, JSONObject.toJSONString(param));
        log.info(log_suffix + "发送请求：{}，入参：{}，出参：{}", agentPayParamDTO.getUri() + uri, JSONObject.toJSONString(param), result);
        JSONObject jResult = JSONObject.parseObject(result);
        if (!jResult.getInteger("code").equals(FuSuiLingGongUtil.SUCCESS_CODE)) {
            return Result.builder().fail(BizCodeMessages.UNKNOWN_ERROR, jResult.getString("msg"));
        }
        if (Objects.isNull(response)) {
            return Result.builder().success();
        }
        if(Objects.equals(uri, "/api/open/queryPeopleList")) {
            String rDATA = jResult.getString("data");
            String newStr = rDATA.replace("[", "");
            String newStr1 = newStr.replace("]", "");
            return Result.builder().success(JSONObject.parseObject(newStr1, response));
        }
        return Result.builder().success(JSONObject.parseObject(jResult.getString("data"), response));
    }

    @Override
    public BigDecimal getBalance() {
        Result<QueryAmountResponse> result = doRequest("/api/open/queryAmount", "{}", QueryAmountResponse.class);

        BigDecimal balance = BigDecimal.ZERO;
        if (result.isSuccess()) {
            balance = result.getData().getAvailableAmount();
            if (CollectionUtils.isNotEmpty(result.getData().getPayAccounts())) {
                for (QueryAmountResponse.PayAccount payAccount : result.getData().getPayAccounts()) {
                    if (StringUtils.equals(payAccount.getPayType(), "银行卡")) {
                        balance = payAccount.getAvailableAmount();
                        break;
                    }
                }
            }
        }
        log.info("福穗灵工查询余额：{}", balance);
        return balance;
    }
}
